#include "common.h"
#include "message_pump.h"
#include "popwin.h"
#include "options.h"
#include "str_utils.h"

HMODULE hUserDll;
BOOL (WINAPI *MySetLayeredWindowAttributes)(HWND,COLORREF,BYTE,DWORD) = 0;
BOOL (WINAPI *MyAnimateWindow)(HWND hWnd,DWORD dwTime,DWORD dwFlags) = 0;

//DWORD message_pump_thread_id = 0;
unsigned int message_pump_thread_id = 0;
HANDLE hMPEvent;

//DWORD CALLBACK MessagePumpThread(LPVOID param) {
unsigned int CALLBACK MessagePumpThread(void *param) {
	if(param) SetEvent((HANDLE)param);

	CallService(MS_SYSTEM_THREAD_PUSH, 0, 0);

	HWND hwndTip = 0;

	MSG hwndMsg = {0};
	while(GetMessage(&hwndMsg, 0, 0, 0) > 0 && !Miranda_Terminated()) {
		if(!IsDialogMessage(hwndMsg.hwnd, &hwndMsg)) {
			switch(hwndMsg.message) {
				case MUM_CREATEPOPUP:
					{
						if(hwndTip) DestroyWindow(hwndTip);
						// if child of clist, zorder is right, but it steals the first click on a contact :(

						// copy topmost exstyle from clist, since we'll put clist under tip in WM_CREATE message
						//LONG clist_exstyle = GetWindowLong((HWND)CallService(MS_CLUI_GETHWND, 0, 0), GWL_EXSTYLE);
						//hwndTip = CreateWindowEx((clist_exstyle & WS_EX_TOPMOST), POP_WIN_CLASS, _T("TipperPopup"), WS_POPUP, 0, 0, 0, 0, 0/*(HWND)CallService(MS_CLUI_GETHWND, 0, 0)*/, 0, hInst, (LPVOID)hwndMsg.lParam);

						hwndTip = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TOPMOST, POP_WIN_CLASS, _T("TipperPopup"), WS_POPUP, 0, 0, 0, 0, 0/*(HWND)CallService(MS_CLUI_GETHWND, 0, 0)*/, 0, hInst, (LPVOID)hwndMsg.lParam);
						if(hwndMsg.lParam) free((LPVOID)hwndMsg.lParam);
					}
					break;

				case MUM_DELETEPOPUP:
					{
						if(hwndTip) {
							DestroyWindow(hwndTip);
							hwndTip = 0;
						}
					}
					break;
				case MUM_GOTSTATUS:
					{
						if(hwndTip) SendMessage(hwndTip, PUM_SETSTATUSTEXT, hwndMsg.wParam, hwndMsg.lParam);
						else if(hwndMsg.lParam) free((void *)hwndMsg.lParam);
					}
					break;
				case MUM_GOTAVATAR:
					{
						if(hwndTip) SendMessage(hwndTip, PUM_SETAVATAR, hwndMsg.wParam, hwndMsg.lParam);
					}
					break;
				default:
					{
						TranslateMessage(&hwndMsg);
						DispatchMessage(&hwndMsg);
					}
					break;
			}
		}
	}

	CallService(MS_SYSTEM_THREAD_POP, 0, 0);

	return 0;
}

void PostMPMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
	PostThreadMessage(message_pump_thread_id, msg, wParam, lParam);
}

// given a popup data pointer, and a handle to an event, this function
// will post a message to the message queue which will set the hwnd value
// and then set the event...so create an event, call this function and then wait on the event
// when the event is signalled, the hwnd will be valid
void FindWindow(POPUPDATAW *pd, HANDLE hEvent, HWND *hwnd);

void InitMessagePump() {
	WNDCLASS popup_win_class = {0};
	popup_win_class.style = 0;
	popup_win_class.lpfnWndProc = PopupWindowProc;
	popup_win_class.hInstance = hInst;
	popup_win_class.lpszClassName = POP_WIN_CLASS;
	popup_win_class.hCursor = LoadCursor(NULL, IDC_ARROW); 
	RegisterClass(&popup_win_class);

	hUserDll = LoadLibrary(_T("user32.dll"));
	if (hUserDll) {
		MySetLayeredWindowAttributes = (BOOL (WINAPI *)(HWND,COLORREF,BYTE,DWORD))GetProcAddress(hUserDll, "SetLayeredWindowAttributes");
		MyAnimateWindow=(BOOL (WINAPI*)(HWND,DWORD,DWORD))GetProcAddress(hUserDll,"AnimateWindow");
	}

	hMPEvent = CreateEvent(0, TRUE, 0, 0);
	CloseHandle((HANDLE)_beginthreadex(0, 0, MessagePumpThread, hMPEvent, 0, &message_pump_thread_id));
	WaitForSingleObject(hMPEvent, INFINITE);
	CloseHandle(hMPEvent);
}

void DeinitMessagePump() {
	PostMPMessage(WM_QUIT, 0, 0);

	FreeLibrary(hUserDll);

	UnregisterClass(POP_WIN_CLASS, hInst);
}

int ShowTip(WPARAM wParam, LPARAM lParam) {
	CLCINFOTIP *clcit = (CLCINFOTIP *)lParam;
	if(clcit->isGroup) return 0; // no group tips (since they're pretty useless)
	if(clcit->isTreeFocused == 0 && options.show_no_focus == false) return 0;

	CLCINFOTIPEX *clcit2 = (CLCINFOTIPEX *)malloc(sizeof(CLCINFOTIPEX));
	memcpy(clcit2, clcit, sizeof(CLCINFOTIP));
	clcit2->cbSize = sizeof(CLCINFOTIPEX);
	clcit2->proto = 0;
	clcit2->text = 0;

	if(wParam) { // wParam is char pointer containing text - e.g. status bar tooltip
		clcit2->text = a2t((char *)wParam);
		GetCursorPos(&clcit2->ptCursor);

		//MessageBox(0, clcit2->text, _T("ShowTip"), MB_OK);
	}

	PostMPMessage(MUM_CREATEPOPUP, 0, (LPARAM)clcit2);
	return 1;
}

int ShowTipW(WPARAM wParam, LPARAM lParam) {
	CLCINFOTIP *clcit = (CLCINFOTIP *)lParam;
	if(clcit->isGroup) return 0; // no group tips (since they're pretty useless)
	if(clcit->isTreeFocused == 0 && options.show_no_focus == false) return 0;

	CLCINFOTIPEX *clcit2 = (CLCINFOTIPEX *)malloc(sizeof(CLCINFOTIPEX));
	memcpy(clcit2, clcit, sizeof(CLCINFOTIP));
	clcit2->cbSize = sizeof(CLCINFOTIPEX);
	clcit2->proto = 0;
	clcit2->text = 0;

	if(wParam) { // wParam is char pointer containing text - e.g. status bar tooltip
		clcit2->text = _tcsdup((TCHAR *)wParam);
		GetCursorPos(&clcit2->ptCursor);
	}

	PostMPMessage(MUM_CREATEPOPUP, 0, (LPARAM)clcit2);
	return 1;
}

int HideTip(WPARAM wParam, LPARAM lParam) {
	//CLCINFOTIP *clcit = (CLCINFOTIP *)lParam;
	PostMPMessage(MUM_DELETEPOPUP, 0, 0);
	return 1;
}

int ProtoAck(WPARAM wParam, LPARAM lParam) {
	ACKDATA *ack = (ACKDATA *)lParam;
	char *szMsg = (char *)ack->lParam;
	if(ack->type == ACKTYPE_AWAYMSG && ack->result == ACKRESULT_SUCCESS && szMsg && szMsg[0]) {
		PostMPMessage(MUM_GOTSTATUS, (WPARAM)ack->hContact, (LPARAM)a2t(szMsg));
	}
	return 0;
}

int FramesShowSBTip(WPARAM wParam, LPARAM lParam) {
	if(options.status_bar_tips) {
		char *proto = (char *)wParam;

		CLCINFOTIPEX *clcit2 = (CLCINFOTIPEX *)malloc(sizeof(CLCINFOTIPEX));
		memset(clcit2, 0, sizeof(CLCINFOTIPEX));
		clcit2->cbSize = sizeof(CLCINFOTIPEX);
		clcit2->proto = proto; // assume static string
		GetCursorPos(&clcit2->ptCursor);

		PostMPMessage(MUM_CREATEPOPUP, 0, (LPARAM)clcit2);

		return 1;
	}
	return 0;
}

int FramesHideSBTip(WPARAM wParam, LPARAM lParam) {
	if(options.status_bar_tips) {
		PostMPMessage(MUM_DELETEPOPUP, 0, 0);
		return 1;
	}
	return 0;
}

